/*  ----------------------------------------------------------------------------
 *  Arello Mobile
 *  Fast 3d Engine
 *  ----------------------------------------------------------------------------
 * Except where otherwise noted, this work is licensed under
 * http://creativecommons.org/licenses/by/3.0
 */

#include "Animation.h"
#include <resource/Resource.h>
#include <resource/Manager.h>
#include <xml/Stream.h>

namespace liba
{
namespace lib2d
{
namespace objects
{

AnimationRep::AnimationRep( const filesystem::String & name )
{
	AutoPtr< resource::Resource > res = resource::Manager::create_resource( name +".ani");
	xml::StreamResource( res ).load( &xml::Root( this, "Animation" ) );
}

bool AnimationRep::on_node( xml::Provider * prov, const std::string & name )
{
	if( name == "Sequence" )
	{
		sequences.push_back( Sequence() );
		return prov->parse_object( &sequences.back() );
	}
	return false;
}

Sequence * AnimationRep::find_sequence( const Atom & name )
{
	std::list< Sequence >::iterator it = sequences.begin();
	for( ; it != sequences.end(); ++it )
	{
		if( it->get_name() == name )
			return &*it;
	}
	return 0;
}

Animation::Animation( const filesystem::String & name )
:	sequence( 0 ),
	frame( 0 ),
	time( 0 ),
	loop_direction( +1 ),
	finished( true ),
	alpha( 255 )
{
	load_rep( name );
}

bool Animation::start( const Atom & name )
{
	sequence = get_rep()->find_sequence( name );
	if( !sequence )
		return false;

	frame = 0;
	time = 0;
	loop_direction = +1;
	finished = false;
	return true;
}

void Animation::life_cycle( float delta_time )
{
	if( finished || !sequence )
		return;
	time += delta_time;
	while( time > sequence->get_frame_duration() )
	{
		time -= sequence->get_frame_duration();
		frame += loop_direction;
		if( frame >= sequence->get_frames_count() )
		{
			if( sequence->get_loop_type() == Sequence::FORWARD )
				frame = 0;
			else
			if( sequence->get_loop_type() == Sequence::PING_PONG )
			{
				loop_direction = -1;
				frame -= 2;
				if( frame < 0 )
					frame = 0;
			}
			else
			{
				--frame;
				time = 0;
				finished = true;
			}
		}
		else
		if( frame < 0 )
		{
			loop_direction = +1;
			frame += 2;
			if( frame >= sequence->get_frames_count() )
				frame = sequence->get_frames_count() - 1;
		}
	}
}

void Animation::render( hard::Renderer * rend )
{
	if( !sequence )
		return;

	int delta_x( 0 );
	int delta_y( 0 );

	switch( sequence->get_align_x() )
	{
	case Sequence::AX_LEFT:
		delta_x = 0;	//default is LEFT-TOP alignment
		break;
	case Sequence::AX_RIGHT:
		delta_x = -sequence->get_width();
		break;
	default:	//CENTER
		delta_x = -sequence->get_width()/2;
		break;
	}

	switch( sequence->get_align_y() )
	{
	case Sequence::AY_TOP:
		delta_y = 0;	//default is LEFT-TOP alignment
		break;
	case Sequence::AY_BOTTOM:
		delta_y = -sequence->get_height();
		break;
	default:	//CENTER
		delta_y = -sequence->get_height()/2;
		break;
	}

	rend->push_shift_add( Vector2( delta_x, delta_y ) );
	sequence->render_frame( rend, Vector2( 0, 0 ), frame, alpha );
	rend->pop_shift();
}

} //namespace objects
} //namespace lib2d
} //namespace liba

